/**
 * The contents of this file are subject to the license and copyright detailed in the LICENSE and NOTICE files at the root of the source tree and available online at
 * http://www.askosi.org/license.html
 */
package be.destin.skos.view;

import java.util.Collection;
import java.util.LinkedList;
import java.util.TreeMap;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

import be.destin.skos.core.Concept;
import be.destin.skos.core.NoScheme;
import be.destin.skos.core.ReferringApplicationList;
import be.destin.skos.core.SchemeInterface;
import be.destin.skos.core.SkosManager;
import be.destin.skos.html.SkosHtmlManager;

/**
 * @author Christophe Dupriez
 * 
 */
@XmlType(propOrder={"prefLabel","icon","url","uri","namespace","usage","narrowerUsage","broader","narrower"})
public class ViewConcept {

	private Concept base;
	private SkosView view;
	private int depth = 1; // TOP by default

	public ViewConcept () {
		super();
	}

	public ViewConcept (SkosView aList, Concept anEntry, int depth) {
		super();
		this.view = aList;
		this.base = anEntry;
		this.depth = depth;
	}
	/**
	 * @return the code
	 */
	@XmlID
	@XmlAttribute(required = true)
	public String getScheme_About() {
		return base.getScheme_About();
	}

	@XmlAttribute
	public String getAbout() {
		return base.getAbout();
	}

	/**
	 * @return the parents
	 */
	@XmlElement
	public LinkedList<String> getBroader() {
		return base.getAboutBroader();
	}
	
	/**
	 * @return the base
	 */
	@XmlTransient
	public Concept getConcept() {
		return this.base;
	}

	/**
	 * @return the children
	 */
	@XmlElement
	public LinkedList<ViewConcept> getNarrower() {
		if (base==null) return null;
		SkosManager skosManager = view.getSkosHtmlManager().getSkosManager();
		if (skosManager == null) return null;
		if (view.getType() != SkosViewType.TREE) return null; // Only trees have a depth...
		if (depth >= Concept.maxDepth) return null; // Deeper is not possible!
		TreeMap<String,ViewConcept> sorter = new TreeMap<String,ViewConcept>();
		SchemeInterface aList = skosManager.getScheme(view.getAbout());
		Collection<String> baseChildren = this.base.getAboutNarrower();
		view.setSomeRejects(false);
		if (baseChildren != null) {
			for (String aChild : baseChildren) {
				if (view.filteredEntries == null || view.filteredEntries.contains(aList.getAbout_About(aChild))) {
					Concept anEntry = aList.getConcept(aChild);
					if (anEntry != null) {
						sorter.put(anEntry.getSortLabel(view.getLang()),new ViewConcept (view, anEntry ,depth+1) );
					}
				} else view.setSomeRejects(true);
			}
		}
		baseChildren = this.base.getScheme_AboutNarrowMatch();
		if (baseChildren != null) {
			for (String aChild : baseChildren) {
				if (view.filteredEntries == null || view.filteredEntries.contains(aChild)) {
					Concept anEntry = skosManager.getScheme_Concept(aChild);
					if (anEntry != null) {
						sorter.put(anEntry.getSortLabel(view.getLang()),new ViewConcept (view, anEntry ,depth+1) );
					}
				}
			}
		}
		if (sorter.size() == 0) return null;
		LinkedList<ViewConcept> children = new LinkedList<ViewConcept>();
		for (ViewConcept aViewConcept : sorter.values()) {
			children.add(aViewConcept);
		}
		return children;
	}

	/**
	 * @return all the aggregatedChildrenUsages
	 */
	@XmlElement
	public ReferringApplicationList getNarrowerUsage() {
		return this.base.getNarrowerUsage();
	}

	/**
	 * @return the names
	 */
	@XmlElement
	public String getPrefLabel() {
		return this.base.getPrefLabel(view.getLang(), false);
	}

	/**
	 * @return the associated icon
	 */
	@XmlElement
	public String getIcon() {
		return this.base.getIconAdapted(view.getSkosHtmlManager());
	}

	/**
	 * @return the associated URL
	 */
	@XmlElement
	public String getUrl() {
		return this.base.getUrlAdapted(view.getSkosHtmlManager());
	}

	/**
	 * @return the URI which identifies the Concept
	 */
	@XmlElement
	public String getUri() {
		SkosHtmlManager skosHtmlManager = this.view.getSkosHtmlManager();
		if (view.getAbout().equals(SkosManager.aboutMetaScheme)) { // Not the URI of the enclosing scheme but the URI of schemes themselves
			SchemeInterface aScheme = skosHtmlManager.getSkosManager().getScheme(this.base.getAbout());
			if (aScheme != null) return ((NoScheme)aScheme).toUriScheme(skosHtmlManager);
		}
		return this.base.toUriConcept(skosHtmlManager);
	}

	/**
	 * @return the namespace which prefixes the Concepts in a (Meta)Scheme. Always NULL for other Schemes
	 */
	@XmlElement
	public String getNamespace() {
		SkosHtmlManager skosHtmlManager = this.view.getSkosHtmlManager();
		if (view.getAbout().equals(SkosManager.aboutMetaScheme)) { // Not the URI of the enclosing scheme but the URI of schemes themselves
			SchemeInterface aScheme = skosHtmlManager.getSkosManager().getScheme(this.base.getAbout());
			if (aScheme != null) return ((NoScheme)aScheme).toUriNamespace(skosHtmlManager);
		}
		return null;
	}

	/**
	 * @return the usages
	 */
	@XmlElement
	public ReferringApplicationList getUsage() {
		return this.base.getUsage();
	}

	/**
	 * @param base the base to set
	 */
	public void setConcept(Concept base) {
		this.base = base;
	}

	/**
	 * @param aggregatedChildrenUsages
	 *            the aggregatedChildrenUsages to set
	 */
	public void setNarrowerUsage(
			ReferringApplicationList aggregatedChildrenUsages) {
		this.base.setNarrowerUsage(aggregatedChildrenUsages);
	}

	public String toString() {
		String aName = this.getPrefLabel();
		if ( aName == null) aName = "no name";
		return "[" + getScheme_About() + "=" + aName + "]";
	}

	/**
	 * @return the skosManager
	 */
	@XmlTransient
	public SkosManager getSkosManager() {
		return view.getSkosHtmlManager().getSkosManager();
	}
}
